import os
import uuid
import tempfile
import time
import threading
from flask import Flask, request, jsonify, send_file, send_from_directory
from PIL import Image
from werkzeug.utils import secure_filename

app = Flask(__name__)
app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024  # 限制文件大小为16MB

# 获取当前文件所在目录
CURRENT_DIR = os.path.dirname(os.path.abspath(__file__))

# 创建临时目录用于存储上传和转换的文件（在项目目录下）
TEMP_DIR = os.path.join(CURRENT_DIR, 'temp_ico_converter')
os.makedirs(TEMP_DIR, exist_ok=True)

# 存储文件信息，用于清理过期文件
file_records = {}

# 请求防抖机制 - 存储IP地址和最后请求时间
request_tracker = {}

# 防抖时间间隔（秒）
DEBOUNCE_INTERVAL = 2

# 链接有效时间（秒）- 设置为5分钟
LINK_EXPIRY_TIME = 5 * 60

# 首页路由
@app.route('/')
def index():
    """首页路由，提供前端页面"""
    index_path = os.path.join(CURRENT_DIR, 'index.html')
    if os.path.exists(index_path):
        return send_file(index_path)
    else:
        # 调试信息
        return f"文件未找到。当前目录: {CURRENT_DIR}, 查找路径: {index_path}", 404

@app.route('/index')
def index_page():
    """显式index路由"""
    return index()

def is_request_allowed(ip_address):
    """检查请求是否被允许（防抖机制）"""
    current_time = time.time()
    if ip_address in request_tracker:
        last_request_time = request_tracker[ip_address]
        if current_time - last_request_time < DEBOUNCE_INTERVAL:
            return False  # 请求太频繁
    # 更新请求时间
    request_tracker[ip_address] = current_time
    return True

def cleanup_expired_files():
    """定期清理过期文件（现在设置为5分钟）"""
    while True:
        current_time = time.time()
        expired_files = []
        
        # 找出过期的文件
        for file_id, record in list(file_records.items()):
            if current_time - record['timestamp'] > LINK_EXPIRY_TIME:  # 5分钟
                expired_files.append((file_id, record))
        
        # 删除过期文件
        for file_id, record in expired_files:
            try:
                # 如果是多文件记录
                if 'files' in record:
                    for file_info in record['files']:
                        if os.path.exists(file_info['path']):
                            os.remove(file_info['path'])
                # 如果是单文件记录
                elif 'path' in record and os.path.exists(record['path']):
                    os.remove(record['path'])
                file_records.pop(file_id, None)
            except Exception as e:
                print(f"清理过期文件时出错: {e}")
        
        # 每隔1分钟检查一次
        time.sleep(60)

def convert_to_icon(input_path, output_path, platform='win'):
    """将图片转换为图标文件"""
    try:
        img = Image.open(input_path)
        print(f"开始转换图片: {input_path}, 平台: {platform}")
        
        # 定义各平台的标准尺寸
        platform_sizes = {
            'win': [(16,16), (32,32), (48,48), (64,64), (128,128), (256,256)],
            'mac': [(16,16), (32,32), (64,64), (128,128), (256,256), (512,512), (1024,1024)],
            'linux': [(32,32), (48,48), (64,64), (128,128), (256,256)]
        }
        
        # 获取基础文件名（不含路径和扩展名）
        base_dir = os.path.dirname(output_path)
        base_name = os.path.basename(output_path)
        
        if platform == 'win':
            # Windows - 为每个尺寸生成单独的ICO文件
            sizes = platform_sizes[platform]
            output_files = []
            for size in sizes:
                resized_img = img.resize(size, Image.Resampling.LANCZOS)
                # 优化文件名：包含平台和尺寸信息
                size_output_path = os.path.join(base_dir, f"{base_name}_win_{size[0]}x{size[1]}.ico")
                resized_img.save(size_output_path, format='ICO')
                output_files.append(size_output_path)
                print(f"已生成文件: {size_output_path}")
            return output_files
        elif platform == 'mac':
            # Mac - 为每个尺寸生成单独的PNG文件
            sizes = platform_sizes[platform]
            output_files = []
            for size in sizes:
                resized_img = img.resize(size, Image.Resampling.LANCZOS)
                # 优化文件名：包含平台和尺寸信息
                size_output_path = os.path.join(base_dir, f"{base_name}_mac_{size[0]}x{size[1]}.png")
                resized_img.save(size_output_path, format='PNG')
                output_files.append(size_output_path)
                print(f"已生成文件: {size_output_path}")
            return output_files
        else:  # linux
            # Linux - 为每个尺寸生成单独的PNG文件
            sizes = platform_sizes[platform]
            output_files = []
            for size in sizes:
                resized_img = img.resize(size, Image.Resampling.LANCZOS)
                # 优化文件名：包含平台和尺寸信息
                size_output_path = os.path.join(base_dir, f"{base_name}_linux_{size[0]}x{size[1]}.png")
                resized_img.save(size_output_path, format='PNG')
                output_files.append(size_output_path)
                print(f"已生成文件: {size_output_path}")
            return output_files
            
        return True
    except Exception as e:
        print(f"转换图标时出错: {e}")
        return False

@app.route('/convert', methods=['POST'])
def convert_image():
    """API接口：将上传的图片转换为图标"""
    # 获取客户端IP地址
    client_ip = request.environ.get('HTTP_X_REAL_IP', request.remote_addr)
    
    # 检查请求是否被允许（防抖机制）
    if not is_request_allowed(client_ip):
        return jsonify({'error': '请求过于频繁，请稍后再试'}), 429
    
    try:
        print("收到转换请求")
        # 检查是否有文件上传
        if 'file' not in request.files:
            return jsonify({'error': '没有上传文件'}), 400
        
        file = request.files['file']
        if file.filename == '':
            return jsonify({'error': '未选择文件'}), 400
            
        # 获取平台参数，默认为Windows
        platform = request.form.get('platform', 'win')
        if platform not in ['win', 'mac', 'linux']:
            platform = 'win'
        
        print(f"平台参数: {platform}")
        
        # 生成唯一的文件ID
        file_id = str(uuid.uuid4())
        # 确保filename是字符串类型
        filename = secure_filename(str(file.filename)) if file.filename else f"upload_{file_id}"
        file_ext = os.path.splitext(filename)[1].lower()
        
        # 检查文件类型
        allowed_extensions = {'.png', '.jpg', '.jpeg', '.bmp'}
        if file_ext not in allowed_extensions:
            return jsonify({'error': '不支持的文件格式，请上传PNG、JPG或BMP格式的图片'}), 400
        
        # 保存上传的文件
        input_path = os.path.join(TEMP_DIR, f"{file_id}_input{file_ext}")
        file.save(input_path)
        print(f"文件已保存到: {input_path}")
        
        # 确定输出文件基础名
        original_name = os.path.splitext(filename)[0]
        output_base_name = f"{original_name}_{platform}"
        output_base_path = os.path.join(TEMP_DIR, f"{file_id}_output")
        print(f"输出基础路径: {output_base_path}")
        
        # 转换图片
        result = convert_to_icon(input_path, output_base_path, platform)
        print(f"转换结果: {result}")
        print(f"结果类型: {type(result)}")
        
        if result is False:
            return jsonify({'error': '图片转换失败'}), 500
        
        # 如果返回的是文件列表（多文件模式）
        if isinstance(result, list):
            print("使用多文件模式")
            # 记录所有生成的文件
            output_files = []
            for file_path in result:
                output_files.append({
                    'path': file_path,
                    'filename': os.path.basename(file_path)
                })
            
            file_records[file_id] = {
                'files': output_files,
                'timestamp': time.time()
            }
            
            # 返回下载链接列表
            download_urls = [f"/download/{file_id}?index={i}" for i in range(len(output_files))]
            # 创建用户友好的文件名列表
            user_friendly_filenames = []
            for file_path in result:
                # 从文件路径中提取尺寸信息
                basename = os.path.basename(file_path)
                # 提取尺寸信息（例如：16x16, 32x32等）
                parts = basename.split('_')
                if len(parts) >= 4:
                    size_info = parts[-1].replace('.ico', '').replace('.png', '')
                    platform_info = parts[-2]
                    original_name = '_'.join(parts[:-2])
                    user_friendly_name = f"{original_name}_{platform_info}_{size_info}.{file_path.split('.')[-1]}"
                else:
                    user_friendly_name = basename
                user_friendly_filenames.append(user_friendly_name)
                
            return jsonify({
                'success': True,
                'file_id': file_id,
                'download_urls': download_urls,
                'filenames': user_friendly_filenames
            })
        else:
            print("使用单文件模式")
            # 单文件模式（保持向后兼容）
            output_ext = '.ico' if platform == 'win' else '.png'
            output_filename = f"{output_base_name}{output_ext}"
            output_path = f"{output_base_path}{output_ext}"
            
            # 记录文件信息
            file_records[file_id] = {
                'path': output_path,
                'filename': output_filename,
                'timestamp': time.time()
            }
            
            # 返回下载链接
            download_url = f"/download/{file_id}"
            return jsonify({
                'success': True,
                'file_id': file_id,
                'download_url': download_url,
                'filename': output_filename
            })
        
    except Exception as e:
        print(f"转换过程中出错: {e}")
        return jsonify({'error': f'服务器内部错误: {str(e)}'}), 500

@app.route('/download/<file_id>')
def download_file(file_id):
    """提供文件下载"""
    try:
        # 检查文件是否存在
        if file_id not in file_records:
            return jsonify({'error': '文件不存在或已过期'}), 404
            
        record = file_records[file_id]
        
        # 获取索引参数（用于多文件下载）
        index = request.args.get('index', type=int)
        
        # 多文件模式
        if 'files' in record:
            files = record['files']
            if index is not None:
                # 下载指定索引的文件
                if index < 0 or index >= len(files):
                    return jsonify({'error': '文件索引超出范围'}), 400
                
                file_info = files[index]
                file_path = file_info['path']
                filename = file_info['filename']
            else:
                # 默认下载第一个文件
                if not files:
                    return jsonify({'error': '没有可下载的文件'}), 404
                file_info = files[0]
                file_path = file_info['path']
                filename = file_info['filename']
        # 单文件模式
        elif 'path' in record:
            file_path = record['path']
            filename = record['filename']
        else:
            return jsonify({'error': '文件记录格式错误'}), 500
        
        # 检查文件路径是否在临时目录中（安全检查）
        if not os.path.abspath(file_path).startswith(os.path.abspath(TEMP_DIR)):
            return jsonify({'error': '无效的文件路径'}), 400
        
        if not os.path.exists(file_path):
            return jsonify({'error': '文件不存在'}), 404
            
        # 更新访问时间
        record['timestamp'] = time.time()
        
        # 提供文件下载
        return send_file(
            file_path,
            as_attachment=True,
            download_name=filename
        )
    except Exception as e:
        return jsonify({'error': f'下载文件时出错: {str(e)}'}), 500

@app.route('/health')
def health_check():
    """健康检查接口"""
    return jsonify({'status': 'ok', 'message': 'ICO转换服务运行正常'})

if __name__ == '__main__':
    # 启动清理过期文件的后台线程
    cleanup_thread = threading.Thread(target=cleanup_expired_files, daemon=True)
    cleanup_thread.start()
    
    # 运行Flask应用
    app.run(host='0.0.0.0', port=5000, debug=False)